<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>doc</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
/* GitHub stylesheet for MarkdownPad (http://markdownpad.com) */
/* Author: Nicolas Hery - http://nicolashery.com */
/* Version: b13fe65ca28d2e568c6ed5d7f06581183df8f2ff */
/* Source: https://github.com/nicolahery/markdownpad-github */

/* RESET
=============================================================================*/

html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
}

/* BODY
=============================================================================*/

body {
  font-family: Helvetica, arial, freesans, clean, sans-serif;
  font-size: 14px;
  line-height: 1.6;
  color: #333;
  background-color: #fff;
  padding: 20px;
  max-width: 960px;
  margin: 0 auto;
}

body>*:first-child {
  margin-top: 0 !important;
}

body>*:last-child {
  margin-bottom: 0 !important;
}

/* BLOCKS
=============================================================================*/

p, blockquote, ul, ol, dl, table, pre {
  margin: 15px 0;
}

/* HEADERS
=============================================================================*/

h1, h2, h3, h4, h5, h6 {
  margin: 20px 0 10px;
  padding: 0;
  font-weight: bold;
  -webkit-font-smoothing: antialiased;
}

h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
  font-size: inherit;
}

h1 {
  font-size: 28px;
  color: #000;
}

h2 {
  font-size: 24px;
  border-bottom: 1px solid #ccc;
  color: #000;
}

h3 {
  font-size: 18px;
}

h4 {
  font-size: 16px;
}

h5 {
  font-size: 14px;
}

h6 {
  color: #777;
  font-size: 14px;
}

body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
  margin-top: 0;
  padding-top: 0;
}

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
  margin-top: 0;
  padding-top: 0;
}

h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
  margin-top: 10px;
}

/* LINKS
=============================================================================*/

a {
  color: #4183C4;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

/* LISTS
=============================================================================*/

ul, ol {
  padding-left: 30px;
}

ul li > :first-child, 
ol li > :first-child, 
ul li ul:first-of-type, 
ol li ol:first-of-type, 
ul li ol:first-of-type, 
ol li ul:first-of-type {
  margin-top: 0px;
}

ul ul, ul ol, ol ol, ol ul {
  margin-bottom: 0;
}

dl {
  padding: 0;
}

dl dt {
  font-size: 14px;
  font-weight: bold;
  font-style: italic;
  padding: 0;
  margin: 15px 0 5px;
}

dl dt:first-child {
  padding: 0;
}

dl dt>:first-child {
  margin-top: 0px;
}

dl dt>:last-child {
  margin-bottom: 0px;
}

dl dd {
  margin: 0 0 15px;
  padding: 0 15px;
}

dl dd>:first-child {
  margin-top: 0px;
}

dl dd>:last-child {
  margin-bottom: 0px;
}

/* CODE
=============================================================================*/

pre, code, tt {
  font-size: 12px;
  font-family: Consolas, "Liberation Mono", Courier, monospace;
}

code, tt {
  margin: 0 0px;
  padding: 0px 0px;
  white-space: nowrap;
  border: 1px solid #eaeaea;
  background-color: #f8f8f8;
  border-radius: 3px;
}

pre>code {
  margin: 0;
  padding: 0;
  white-space: pre;
  border: none;
  background: transparent;
}

pre {
  background-color: #f8f8f8;
  border: 1px solid #ccc;
  font-size: 13px;
  line-height: 19px;
  overflow: auto;
  padding: 6px 10px;
  border-radius: 3px;
}

pre code, pre tt {
  background-color: transparent;
  border: none;
}

kbd {
    -moz-border-bottom-colors: none;
    -moz-border-left-colors: none;
    -moz-border-right-colors: none;
    -moz-border-top-colors: none;
    background-color: #DDDDDD;
    background-image: linear-gradient(#F1F1F1, #DDDDDD);
    background-repeat: repeat-x;
    border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
    border-image: none;
    border-radius: 2px 2px 2px 2px;
    border-style: solid;
    border-width: 1px;
    font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
    line-height: 10px;
    padding: 1px 4px;
}

/* QUOTES
=============================================================================*/

blockquote {
  border-left: 4px solid #DDD;
  padding: 0 15px;
  color: #777;
}

blockquote>:first-child {
  margin-top: 0px;
}

blockquote>:last-child {
  margin-bottom: 0px;
}

/* HORIZONTAL RULES
=============================================================================*/

hr {
  clear: both;
  margin: 15px 0;
  height: 0px;
  overflow: hidden;
  border: none;
  background: transparent;
  border-bottom: 4px solid #ddd;
  padding: 0;
}

/* TABLES
=============================================================================*/

table th {
  font-weight: bold;
}

table th, table td {
  border: 1px solid #ccc;
  padding: 6px 13px;
}

table tr {
  border-top: 1px solid #ccc;
  background-color: #fff;
}

table tr:nth-child(2n) {
  background-color: #f8f8f8;
}

/* IMAGES
=============================================================================*/

img {
  max-width: 100%
}
</style>
</head>
<body>
<h1>CrossPHP 框架功能及特点</h1>
<h1>一. 项目基本结构</h1>
<p>在一个 <code>Cross</code> 项目中, 一个项目被拆分为多个app, 放在app目录下, 每个app都包含独立的控制器,视图及模板, 分别用于控制项目的具体部分, 一个常见的项目结构如下:</p>
<pre><code>├─app 应用模块目录    
│  ├─admin 后台模块  
│  │  ├─templates 模板文件夹
│  │  │  └─web   
│  │  ├─controller 控制器目录  
│  │  └─view 视图文件目录 
│  └─home 前台模块  
│     ├─init.php 模块配置文件
│     ├─templates 模板文件夹
│     │  └─web  
│     ├─controller 控制器目录  
│     └─view 视图文件目录    
├─lib 第三方类库 
├─cache 缓存文件目录   
├─config 配置文件目录  
├─modules modules文件夹
│   ├─admin
│   └─common
└─htdocs 可访问目录  
  ├─admin  
  └─home
</code></pre>

<p>每个app的根目录下面,都有一个名为 <code>init.php</code> 的PHP文件, 该配置文件返回一个PHP数组,这个数组默认分为三个部分</p>
<pre><code>├─app 应用模块目录    
│  └─web 网站模块  
│     ├─init.php app配置文件
│     ├─templates
│     │  └─web
│     │      ├─home
│     │      ├─...
│     │      └─default.layer.php 
│     ├─controller
│     └─view 
</code></pre>

<h3>sys</h3>
<p>app默认配置,用于指定默认模板目录等</p>
<ol>
<li><code>auth</code> 默认的认证方式, 使用SESSION或COOKIE.</li>
<li><code>default_tpl_dir</code> 默认模板文件夹路径,可以在控制器中通过 <code>$this-&gt;config-&gt;set('sys', array('default_tpl_dir'=&gt;'name'))</code> 来指定controller项目使用的模板.</li>
<li><code>display</code> 默认的视图处理方法, 默认 <code>HTML</code> 使用视图控制器对应的方法来处理, <code>JSON</code> / <code>XML</code> 直接使用视图控制器中的JSON / XML方法来处理数据.</li>
</ol>
<h3>url</h3>
<p>为每个app指定独立的url风格</p>
<ol>
<li>
<p><code>*</code> 指定默认的控制器和方法.</p>
</li>
<li>
<p><code>type</code> 指定解析url的方式, 其中 <code>1</code>和<code>3</code> 处理<code>QUERY_STRING</code>格式的url, <code>2</code>和<code>4</code>处理<code>PATH_INFO</code>的方式生成的url, 假设生成连接的方法为 <code>$this-&gt;link(&quot;main:index&quot;, array('p1'=&gt;1, 'p2'=&gt;2, 'p3'=&gt;3))</code> 那么根据type的值会生成以下四种风格的url:	</p>
<pre><code>1  skeleton/htdocs/web/?/main/index/1/2/3
3  skeleton/htdocs/web/?/main/index/p1/1/p2/2/p3/3

2  skeleton/htdocs/web/index.php/main/index?p1=1&amp;p2=2&amp;p3=3      
4  skeleton/htdocs/web/index.php/main/index/p1/1/p2/2/p3/3
</code></pre>

<p>由此可见,当 <code>type = 1</code> 的时候生成的url最短. 在控制器中使用 <code>$this-&gt;params</code> 可以获得通过url传递的参数, 当 <code>type = 1</code> 时, 需要在控制器方法的头部使用 <code>@cp_params p1, p2, p3</code> 来指定指定参数的key名称.</p>
</li>
<li>
<p><code>rewrite</code> 用来控制生成url的时候是否隐藏url中的 <code>?</code>号或索引文件名, 当<code>type</code>的值为1或3的时候, apache对应的 <code>.htaccess</code> 文件内容如下:</p>
<pre><code>&lt;IfModule mod_rewrite.c&gt;
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]

RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
RewriteRule ^(.*)$ %{ENV:BASE}index.php?$1 [NC,L]
&lt;/IfModule&gt;
</code></pre>

<p>nginx 配置的rewrite配置如下:</p>
<pre><code>location / {
    if (!-f $request_filename) {
        rewrite ^/(.*)$ /index.php?$1 last;
    }
}
</code></pre>

<p>当<code>type</code>的值为2或4的时候, 把上面两条规则中的 <code>index.php?</code> 替换为 <code>index.php/</code> 即可.</p>
</li>
<li>
<p><code>dot</code> 用来指定生成url路径中的分隔符例如: <code>skeleton/htdocs/web/?/main/index/1/2/3</code>. 这里的dot的值为 <code>/</code>, 如果把dot的值改为 <code>-</code>, 那么重新生成后的url为: <code>skeleton/htdocs/web/?/main-index-1-2-3</code> dot可以指定为浏览器能识别的任何字符.</p>
</li>
<li>
<p><code>ext</code> 用来指定生成url后缀, 假设指定 <code>ext</code> 的值为<code>.html</code> url <code>skeleton/htdocs/web/?/main/index/1/2/3</code> 重新生成的url为 <code>skeleton/htdocs/web/?/main/index/1/2/3.html</code>, 此时会强制检查url后最是否以 <code>.html</code> 结束, 否则会抛出一个找不到该页面的异常.</p>
</li>
<li>
<p><code>index</code> 索引文件名称即htdocs目录对应app文件夹中的默认文件, 默认是 <code>index.php</code> 如果要使用其他的索引文件请修改此处. </p>
</li>
</ol>
<h3>router</h3>
<p>router用于指定控制器的别名, 以以下配置为例:</p>
<pre><code>'router'    =&gt; array(
    'hi'    =&gt;  'main:index',

    'article'   =&gt;  array(
        'page'  =&gt;  'index',
    ),
),
</code></pre>

<p>当请求的url是 <code>skeleton/htdocs/web/?/hi</code> 的时, 实际响应的是 <code>main</code> 控制器中的 <code>index</code> 方法</p>
<p>当请求的url是 <code>skeleton/htdocs/web/?/article/page</code> 的时, 实际响应的控制是 <code>article</code> 的 <code>index</code> 方法  
</p>
<p>在Cross中，路由是双向解析的，生成连接后，如果给连接指定了别名，连接会自动刷新为指定的别名。</p>
<h1>二. 启动框架</h1>
<p>Cross项目 框架和项目 独立， 所以启动框架前需要做两件事</p>
<ol>
<li>
<p>告诉框架项目路径</p>
<pre><code>defined('PROJECT_PATH') or define('PROJECT_PATH', realpath(dirname(__FILE__)) . DIRECTORY_SEPARATOR);
</code></pre>

<p>在引用框架启动文件前需要先告诉框架项目路径， 所以需要先定义一个<code>PROJECT_PATH</code>常量，指向项目目录。</p>
</li>
<li>
<p>告诉项目框架路径</p>
<pre><code>require PROJECT_PATH . '../crossphp/boot.php';
</code></pre>

<p>载入框架引导文件，该文件位于框架的根目录，名为 <code>boot.php</code>, 框架可以放在计算机的任意路径，只要正确的包含进该文件即可。</p>
</li>
</ol>
<h3>指定要启动的APP</h3>
<ol>
<li>
<p>解析url运行</p>
<pre><code>Cross::loadApp('web')-&gt;run();
</code></pre>

<p>此时框架会先载入<code>app\web\init.php</code>文件中的配置，根据配置来解析url， 并调用相应的控制器来处理访问请求</p>
</li>
<li>
<p>调用指定的控制器和方法, 以调用 <code>main</code> 控制器中的 <code>index</code> 方法为例：</p>
<pre><code>Cross::loadApp('web')-&gt;get(&quot;main:index&quot;);
</code></pre>

<p>如果有附加参数，通过<code>get</code>方法的第二个参数传递给控制器</p>
<pre><code>Cross::loadApp('web')-&gt;get(&quot;main:index&quot;, $args);
</code></pre>

</li>
</ol>
<h1>三. 控制器</h1>
<p>在app\web\controllers目录下创建一个User.php文件,文件内容如下:</p>
<pre><code>namespace app\web\controllers;

use Cross\MVC\Controller;
/**
 * @Auth: wonli &lt;wonli@live.com&gt;
 * Class Main
 * @package app\web\controllers
 *
 * @cp_cache array(true, array('type'=&gt;1))
 */
class User extends Controller
{
    function index()
    {
        echo 'hello';
    }
}
</code></pre>

<p>通过浏览器 <code>http://domain/skeleton/htdocs/web/user</code> 来访问,这时页面会输出 <code>hello</code>。<br />
控制器的注释生效（对所有方法的请求都会优先使用缓存）。</p>
<h3>父类提供的方法</h3>
<ol>
<li>
<p>判断请求类型</p>
<pre><code>$this-&gt;is_post() 
$this-&gt;is_get()
$this-&gt;is_cli() 
$this-&gt;is_ajax_request()
</code></pre>

<p>以上方法用于判断当前请求的类型，满足条件返回TRUE</p>
</li>
<li>
<p>跳转到其他控制器</p>
<pre><code>$this-&gt;to([controller:action, params, sec])
</code></pre>

<p>跳转到指定页面,该方法实际是一个 <code>$this-&gt;view-&gt;link()</code> 的连接, 生成url后用header函数跳转.</p>
</li>
<li>
<p>调用视图</p>
<pre><code>$this-&gt;display([data, method, http_response_status])
</code></pre>

<p>调用视图控制，一个<code>$this-&gt;view-&gt;display()</code>的连接。</p>
</li>
</ol>
<blockquote>
<p>建议: 每个app对应该有一个基类控制器,基类控制器继承至<code>Cross\MVC\Controller</code>, 其余控制器从基类继承, 这样更灵活.</p>
</blockquote>
<h3>读取app配置</h3>
<pre><code>namespace app\web\controllers;

use Cross\MVC\Controller;

class User extends Controller
{
    function index()
    {
        $this-&gt;config-&gt;get(&quot;key&quot;[, val])
    }
}
</code></pre>

<p>在控制器中可以通过<code>$this-&gt;config-&gt;get()</code>方法来读取<code>app\web\init.php</code>中的配置项的值，<code>key</code>为配置数组中的键， 如果不指定<code>val</code>则返回该键对应的所有配置。</p>
<h3>设置或更改配置项</h3>
<pre><code>namespace app\web\controllers;

use Cross\MVC\Controller;

class User extends Controller
{
    function index()
    {
        $this-&gt;config-&gt;set(&quot;set&quot;, array('key', 'val'))
    }
}   
</code></pre>

<p>如果app配置文件中有对应的键、值存在，那么修改为指定的值， 没有则添加一项</p>
<h3>获取URL参数</h3>
<p>假设当前的url为 <code>http://domain/skeleton/htdocs/web/controller/action[/p1/1/p2/2]</code>, 在方法内部使用控制器的 <code>$this-&gt;params</code> 属性可以获得参数的值:</p>
<pre><code>namespace app\web\controllers;

use Cross\MVC\Controller;

class User extends Controller
{
    function index()
    {
        print_r($this-&gt;params);
    }
}
</code></pre>

<p>打印结果为一个关联索引数组 此时 <code>skeleton/app/web/init.php</code> 中的值为<code>url['type'] = 3</code></p>
<pre><code>Array ( [p1] =&gt; 1 [p2] =&gt; 2 )
</code></pre>

<blockquote>
<p>要还原参数的key,请参见使用注释配置一节</p>
</blockquote>
<h3>使用注释配置</h3>
<h6>1. 还原参数的key</h6>
<p>在app配置文件url字段字段部分，当type=1时, 在方法体内部使用 <code>$this-&gt;params</code> 属性默认获得的参数是一个数字索引数组,这时可以在方法体的注释中使用 <code>@cp_params</code> 指定了参数的key,格式为 <code>@cp_params 参数1, 参数2...</code> 如下例:</p>
<pre><code>namespace app\web\controllers;

use Cross\MVC\Controller;

class User extends Controller
{
    /**
     * 默认控制器
     * @cp_params p1, p2, p3
     */
    function index()
    {
        print_r($this-&gt;params);
    }
}
</code></pre>

<p>此时打印的结果为：</p>
<pre><code>Array ( [p1] =&gt; 1 [p2] =&gt; 2 [p3] =&gt; 3 ) 
</code></pre>

<p>使用其他模式时打印结果均为</p>
<pre><code>Array ( [p1] =&gt; 1 [p2] =&gt; 2 [p3] =&gt; 3 ) 
</code></pre>

<blockquote>
<p><code>@cp_params</code> 只有<code>type=1</code>时生效， 为保持程序的一致性使用<code>@cp_params</code>时，指定的参数应与生成的连接的参数保存一致 </p>
</blockquote>
<h6>2. 为Action配置缓存</h6>
<p>在注释中使用 <code>@cp_cache</code> 字段指定该Action的缓存,直接使用php数组进行配置</p>
<pre><code>namespace app\web\controllers;

use Cross\MVC\Controller;

class User extends Controller
{
    /**
     * 默认控制器
     * 
     * @cp_cache array(true, array('type'=&gt;1, 'expire_time'=&gt;864000))
     */
    function index()
    {

    }
}
</code></pre>

<p>配置的格式为一个二维数组 <code>array(true/false, array(key=&gt;val...))</code></p>
<p>第一个参数<code>true</code> 或 <code>false</code> 分别代表配置的开关.</p>
<p>第二个参数中公用的有</p>
<pre><code>expire_time 表示缓存过期时间
key 缓存文件key的生成规则,支持匿名函数, 该匿名函数接收两个参数,第一个是app_name,controller,action, 第二个是params.
</code></pre>

<p>a. 使用文件缓存 <code>array(true, array('type'=&gt;1, 'expire_time'=&gt;864000))</code></p>
<pre><code>type = 1
cache_path 表示缓存文件放在web索引文件的跟目录,默认放在项目的cache/request文件夹下
file_ext 缓存文件扩展名 默认为sys display中配置的处理方法名
</code></pre>

<blockquote>
<p>项目根目录下的cache目录需设置为可以读写</p>
</blockquote>
<p>b. 使用memcache缓存 <code>array(true, array('type'=&gt;2, 'host'=&gt;'127.0.0.1', 'port'=&gt;11211, 'expire_time'=&gt;600))</code></p>
<pre><code>type=2
host=127.0.0.1
port=11211
</code></pre>

<p>c. 使用redis缓存 <code>array(true, array('type'=&gt;1, 'host'=&gt;'127.0.0.1', 'db'=&gt;3, 'port'=&gt;6379, expire_time=86400))</code></p>
<pre><code>type=3, 
host=127.0.0.1, 
port=6379, 
db=3 使用的db id
</code></pre>

<p>使用缓存后Dispatcher流程会跳过app模型中该Action的逻辑,直接从缓存读取数据返回给客户端, 合理的使用缓存能大幅度提高应用性能.</p>
<blockquote>
<p>使用op_cache的时候注意与注释相关参数的设置</p>
</blockquote>
<h6>3. 配置前后置</h6>
<p>使用 <code>cp_before</code> 配置运行前要执行的方法，使用 <code>cp_after</code> 配置运行结束后要执行的方法。参数是一个可访问的类方法。</p>
<h6>4. 配置response</h6>
<p>使用 <code>cp_response</code> 配置response，主要用于修正response时，返回的content-type和status。</p>
<h5>5. 配置Basic Auth</h5>
<p>使用 <code>cp_basicAuth</code> 在运行前先发送一个Basic Auth请求到客户端，使用<code>array('user'=&gt;'用户名', 'pw'=&gt;'密码')</code>来指定用户名和密码。</p>
<h5>6. 自定义配置参数</h5>
<p>自定义配置参数的格式为<code>cp_配置名</code>， 参数可以为任意可访问的类/或文件，自定义好以后在自己的类中处理。</p>
<h3>在控制器中使用modules</h3>
<p>在控制器中使用modules,以使用UserModules为例:</p>
<pre><code>namespace app\web\controllers;

use Cross\MVC\Controller;

class User extends Controller
{
    function index()
    {
        $USER = new UserModules();
    }
}
</code></pre>

<p>如果类中每个action都依赖<code>UserModules</code>, 可以把初始化UserModules的工作放到构造函数中:</p>
<pre><code>namespace app\web\controllers;

use Cross\MVC\Controller;

class User extends Controller
{
    /**
     * @var UserModule
     */
    protected $USER;

    function __construct()
    {
        parent::__construct();
        $this-&gt;USER = new UserModule();
    }

    function index()
    {

    }
}
</code></pre>

<p>然后就可以在控制器中调用modules提供的方法了. </p>
<h3>在控制器中使用view</h3>
<h6>1. 基本使用方式</h6>
<pre><code>namespace app\web\controllers;

use Cross\MVC\Controller;

class User extends Controller
{
    function index()
    {
        $page = array(
            'p' =&gt;  isset($this-&gt;params['p'])?intval($this-&gt;params['p']):1,
            'limit' =&gt; 20,
            'half' =&gt; 3,
            'link' =&gt; array(&quot;main:index&quot;),
        );

        $USER = new UserModule();
        $result['data'] = $USER-&gt;getUserList( $page );
        $result['page'] = $page;

        $this-&gt;display($result);
    }
}
</code></pre>

<p>从Modules取出数据和分页信息, 放进变量 <code>$result</code> 中, 传给视图控制器的同名方法处理, 在视图控制器中整理数据, 调用模版, 赋值给布局文件中的 <code>$content</code> 变量, 生成最终的结果页面一起返回到 <code>Dispatcher</code> 中,如果有请求缓存则把结果存进缓存中, 然后通过 <code>Response-&gt;output()</code> 方法发送给用户, 下次请求的时候先检查是否有缓存, 如果有缓存并且还在缓存的有效期, 直接从缓存把结果返回给用户.</p>
<h6>2. 使用视图控制器中指定的Action</h6>
<pre><code>namespace app\web\controllers;

use Cross\MVC\Controller;

class User extends Controller
{
    function index()
    {
        $page = array(
            'p' =&gt;  isset($this-&gt;params['p'])?intval($this-&gt;params['p']):1,
            'limit' =&gt; 20,
            'half' =&gt; 3,
            'link' =&gt; array(&quot;main:index&quot;),
        );

        $USER = new UserModule();
        $result['data'] = $USER-&gt;getUserList( $page );
        $result['page'] = $page;

        $this-&gt;display($result, 'JSON');
    }
}
</code></pre>

<p>使用视图控制器提供的 <code>JSON</code> 方法,返回一个JSON结果.</p>
<h6>3. 不使用layer布局.</h6>
<pre><code>class Main extends CoreController
{
    function index()
    {
        $page = array(
            'p' =&gt;  isset($this-&gt;params['p'])?intval($this-&gt;params['p']):1,
            'limit' =&gt; 20,
            'half' =&gt; 3,
            'link' =&gt; array(&quot;main:index&quot;),
        );

        $USER = new UserModule();
        $result['data'] = $USER-&gt;getUserList( $page );
        $result['page'] = $page;

        if ($this-&gt;is_ajax_request())
        {
            $this-&gt;view-&gt;index($result);
        } else {
            $this-&gt;display($result);
        }
    }
}
</code></pre>

<p>如果是ajax请求不包含layer中的内容.</p>
<h1>四. Module系统</h1>
<pre><code>├─modules modules文件夹
│   ├─admin
│   ├─space
│   ├─user
│   ├─article
│   └─common
</code></pre>

<p>模型系统是所有app功能模块共同的数据来源,一个modules支持多个数据来源.目前默认支持以下的数据库系统.</p>
<ul>
<li>PDO驱动的MySQL，SQLite，PgSQL</li>
<li>Redis,</li>
<li>Memcache,</li>
<li>CouchBase,</li>
<li>MongoDB</li>
</ul>
<p>除了这些默认支持的数据库外， 在数据库配置文件中，还可以将参数配置为一个匿名函数，来自定义你自己的数据处理类。</p>
<blockquote>
<p>不支持不同类型数据库之间切换</p>
</blockquote>
<h3>连接默认数据库</h3>
<p>在项目的根目录下的modules文件夹中创建web文件夹, 在web文件夹下创建 <code>ApiModule.php</code> 内容如下:</p>
<pre><code>namespace modules\web;

use Cross\MVC\Module;

class ApiModule extends Module
{
    function __construct()
    {
        parent::__construct();
    }
}
</code></pre>

<h3>连接指定数据库</h3>
<p><code>parent::__construct()</code> 中的参数为要连接的数据库的配置的名称,默认连接的数据库为<code>mysql:db</code>,参数格式为:</p>
<pre><code>数据库类型:配置名称  
</code></pre>

<p>通过config目录下的db.config.php 指定, 比如要连接log数据库 </p>
<pre><code>namespace modules\web;

use Cross\MVC\Module;

class ApiModule extends Module
{
    function __construct()
    {
        parent::__construct(&quot;mysql:log&quot;);
    }
}
</code></pre>

<p>连接数据库后,在modules类中用 <code>$this-&gt;link</code> 来调用数据库驱动提供的接口.</p>
<blockquote>
<p>modules默认不建立与任何数据库系统的连接,只需覆盖默认的构造函数 或不从CoreModule继承.</p>
</blockquote>
<h3>MySQL查询</h3>
<p>假设 <code>modules\web\UserModule.php</code> 中的代码如下：</p>
<pre><code>namespace modules\web;

use Cross\MVC\Module;

class UserModule extends Module
{
    protected $t_user = 'front_user';

    function getUser() 
    {

    }
}
</code></pre>

<p>连接数据库后, 在module的方法中就可以使用 <code>$this-&gt;link</code> 属性使用连接类提供的方法查询了,以MySql类默认提供的查询为例.</p>
<h6>查询单条记录</h6>
<pre><code>function getUser() 
{
    return $this-&gt;link-&gt;get($this-&gt;t_user, '*', 'score=1')
}
</code></pre>

<p>也可以用数组表示</p>
<pre><code>function getUser() 
{
    return $this-&gt;link-&gt;get($this-&gt;t_user, '*', array(
        'score' =&gt; 1
    ));
}
</code></pre>

<h6>查询多条记录</h6>
<pre><code>function getUser() 
{
    return $this-&gt;link-&gt;getAll($this-&gt;t_user, '*');
}
</code></pre>

<h6>条件查询</h6>
<pre><code>function getUser() 
{
    return $this-&gt;link-&gt;getAll($this-&gt;t_user, '*', array(
        'score' =&gt; array('&gt;', 1)
    ));
｝
</code></pre>

<p>查询score 大于 1的用户 类似的操作还可以使用<code>&gt;</code>, <code>&lt;&gt;</code>等。</p>
<pre><code>function getUser() 
{
    return $this-&gt;link-&gt;getAll($this-&gt;t_user, '*', array(
        'name' =&gt; array('like', 'john')
    ));
｝
</code></pre>

<p>使用like查询</p>
<h6>使用IN、OR查询</h6>
<pre><code>function getUser()
{
    return $this-&gt;link-&gt;getAll($this-&gt;t_user, '*', array(
        'id' =&gt; array('in', array(1,2,3))
    ));
}
</code></pre>

<p>对应的sql语句为 <code>SELECT * FROM back_acl_menu WHERE id IN (?,?,?)</code></p>
<pre><code>function getUser()
{
    return $this-&gt;link-&gt;getAll($this-&gt;t_user, '*', array(
            'id' =&gt; array('or', array(1, 2, 3))
        ));
}
</code></pre>

<p>对应的sql语句为： <code>SELECT * FROM front_user WHERE id = ? OR id = ? OR id = ?</code></p>
<h6>为OR中的某一项指定条件</h6>
<pre><code>function getUser()
{
    return $this-&gt;link-&gt;getAll($this-&gt;t_user, '*', array(
            'id' =&gt; array('or', array(1, 2, 3, array('&gt;', 5) ))
        ));
}
</code></pre>

<p>此时生成的sql语句为 <code>SELECT * FROM front_user WHERE id = ? OR id = ? OR id = ? OR id &gt; ?</code></p>
<h6>使用BETWEEN</h6>
<pre><code>function getUser()
{
    return $this-&gt;link-&gt;getAll($this-&gt;t_user, '*', array(
        'id'    =&gt;  array('between', array(1, 2))
    ));
}
</code></pre>

<p>生成的SQL语句模板为 <code>SELECT * FROM front_user WHERE id BETWEEN 1 AND 2</code></p>
<h6>带分页数据的查询</h6>
<pre><code>function getUser(&amp; $page = array('p'=&gt;1, 'limit'=&gt;30))
{
    $this-&gt;link-&gt;find($this-&gt;t_user, '*', array(
        'score' =&gt; array('&gt;', 1),
    ), 'id DESC', $page);
｝
</code></pre>

<h6>混合使用</h6>
<pre><code>function getUser()
{
    return $this-&gt;link-&gt;getAll($this-&gt;t_user, '*', array(
        'id'    =&gt;  array('in', array(7, 2, 3)),
        'pid'   =&gt;  array('or', array(1, 2 =&gt; array('&gt;', 2)))
    ));
}
</code></pre>

<p>生成的sql语句为 <code>SELECT * FROM front_user WHERE id IN (?,?,?) AND pid = ? OR pid &gt; ?</code></p>
<h6>左右连接</h6>
<pre><code>function getUser()
{
    return $this-&gt;link-&gt;getAll(&quot;{$this-&gt;t_user} tu LEFT JOIN front_user_base fub ON tu.id=fub.id&quot;, '*', array(
        'id'    =&gt;  1
    ));
}
</code></pre>

<h3>添加数据</h3>
<p>添加单条记录</p>
<pre><code>function getUser()
{
    $this-&gt;link-&gt;add($this-&gt;t_user, array(
        'score' =&gt; 5,
        'group' =&gt;  1,
    ));
｝
</code></pre>

<blockquote>
<p>如果主键是id返回id, 否则总是返回 <code>true</code></p>
</blockquote>
<p>批量添加 </p>
<pre><code>function getUser()
{       
    $insert_data = array();

    $this-&gt;link-&gt;add($this-&gt;t_user, array(
        'fields' = array('score', 'group'),
        'values' = array(
            array(5, 1),    
            array(5, 2),
            array(5, 3),
        )
    ), true, $insert_data);
｝
</code></pre>

<blockquote>
<p><code>insert_data</code> 返回的值为添加以后结果.</p>
</blockquote>
<h3>删除记录</h3>
<p>删除单条记录</p>
<pre><code>function getUser()
{
    $this-&gt;link-&gt;del($this-&gt;t_user, array(
        'id'=&gt;1
    ));
｝
</code></pre>

<p>批量删除id等于1和id等于2的用户</p>
<pre><code>function getUser()
{
    $this-&gt;link-&gt;del($this-&gt;t_user, array(
        'fields' =&gt; array('id'),
        'values' =&gt; array(
            array(1),
            array(2),
        ),
    ), true);
｝
</code></pre>

<h3>直接执行sql语句</h3>
<p>返回单条记录</p>
<pre><code>function getUser($sql)
{
    $this-&gt;link-&gt;fetchOne($sql, $model = PDO::FETCH_ASSOC);
｝
</code></pre>

<p>返回多条记录</p>
<pre><code>function getUser($sql)
{
    $this-&gt;link-&gt;fetchAll($sql, $model = PDO::FETCH_ASSOC);
｝
</code></pre>

<blockquote>
<p>适用于不带参数的sql查询</p>
</blockquote>
<h3>手动绑定参数</h3>
<blockquote>
<p>$sql =  &quot;select fri.<em>, fue.</em> from ( select * from front_user where uid = ?) fri<br />
left join front<em>user</em>extend fue on fri.id=fue.uid&quot;</p>
</blockquote>
<pre><code>$this-&gt;link-&gt;prepare($sql)-&gt;exec(array(1))-&gt;stmt_fetch(true);
</code></pre>

<h1>五.视图概述</h1>
<pre><code>├─crossboot.php  
│
├─app     
│  ├─admin   
│  └─home   
│     ├─init.php 
│     ├─templates 
│     │  └─web
│     │      ├─home
│     │      ├─main
│     │      ├─user
│     │      ├─...
│     │      └─default.layer.php     
│     ├─controller   
│     └─view 视图控制器文件目录  
</code></pre>

<p>CrossPHP框架中的视图由两个部分组成,即视图控制器和模板系统. </p>
<ol>
<li>
<p>app下的view目录即视图控制器目录,每一个控制器的视图都由一个视图控制器单独处理.视图控制器中的action负责格式化数据,包含模板等操作.</p>
</li>
<li>
<p>模板系统包含模板和布局系统,模板系统中输出的内容先包含进布局中,再输出到浏览器</p>
</li>
</ol>
<h3>模板结构</h3>
<p>CrossPHP默认的模板语言为PHP本身,一个app模板结构如下:</p>
<pre><code>├─templates 模板文件夹
│  ├─default
│  │   ├─acl
│  │   │   ├─list.tpl.php
│  │   │   ├─index.tpl.php  
│  │   │   └─add.tpl.php
│  │   │    
│  │   ├─main
│  │   ├─security
│  │   ├─...
│  │   └─default.layer.php 默认布局文件
│  └─web
│      ├─acl
│      ├─main
│      ├─security
│      ├─...
│      └─default.layer.php 默认布局文件
</code></pre>

<ol>
<li>模板命名方式为目录和控制器中的类一一对应, 模板文件和控制器中的方法对应,即模板名称/控制器名称/方法名称.</li>
<li>布局文件放在模板文件的根目录下.</li>
</ol>
<h3>视图控制器</h3>
<p>视图控制器文件夹位于 <code>app\web\views</code> 目录下， 访问控制器中的类的时候，会自动去视图控制器目录下查找视图控制器文件比如<code>Main</code>控制器默认的视图控制器类名为<code>MainView</code>，文件内容如下:</p>
<pre><code>namespace app\web\views;

use Cross\MVC\View;

class MainView extends View
{
    function index($data = array())
    {   
        include $this-&gt;tpl(&quot;main/index&quot;);
    }
}
</code></pre>

<p>一般视图控制器只是用来载入对应的模板</p>
<blockquote>
<p>ajax返回的时候,不用返回公共的layer文件内容</p>
</blockquote>
<h3>使用布局</h3>
<h6>1. 基本用法</h6>
<p>在控制器中使用<code>$this-&gt;display()</code>方法,必须包含默认的布局文件default.layer.php, 一个空白的布局文件内容如下:</p>
<pre><code>&lt;?php echo isset($content)?$content:'' ?&gt;
</code></pre>

<p><code>$content</code>的内容即控制器中调用<code>$this-&gt;view-&gt;main()</code>输出的内容.一个HTML布局文件内容如下:</p>
<pre><code>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;zh-CN&quot;&gt;
&lt;head&gt;
    &lt;title&gt;&lt;?php echo isset($title)?$title:'' ?&gt;&lt;/title&gt;
    &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=UTF-8&quot; /&gt;
    &lt;meta name=&quot;Keywords&quot; content=&quot;&lt;?php echo isset($keywords)?$keywords:''; ?&gt;&quot; /&gt;
    &lt;meta name=&quot;Description&quot; content=&quot;&lt;?php echo isset($description)?$description:''; ?&gt;&quot; /&gt;
    &lt;link rel=&quot;stylesheet&quot; rev=&quot;stylesheet&quot; href=&quot;&lt;?php echo $this-&gt;res(&quot;css/style.css&quot;) ?&gt;&quot; media=&quot;all&quot; /&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;?php echo isset($content)?$content:'' ?&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>

<p>请求<code>index</code>的时候会自动载入视图控制器目录下面的<code>MainView.php</code>文件,文件内容如下:</p>
<pre><code>namespace app\web\views;

use Cross\MVC\View;

class MainView extends View
{
    function index($data = array())
    {   
        include $this-&gt;tpl(&quot;main/index&quot;);
    }
}
</code></pre>

<p>index方法输出的内容至布局文件中的变量<code>$content</code>,然后合并输出到浏览器.</p>
<h6>2. 在视图控制器中控制布局的内容</h6>
<p>a. 更改网站标题,keywords,和description</p>
<pre><code>    namespace app\web\views;

    use Cross\MVC\View;

    class MainView extends View
    {
        function index($data = array())
        {   
            $this-&gt;set(array(
                'title' =&gt;  'hi',
                'keywords'   =&gt;  'crossphp',
                'description'   =&gt;  '轻量高效php开发框架',
            ));

            include $this-&gt;tpl(&quot;main/index&quot;);
        }
    }

布局文件中的所有变量均可以在action中,调用基类中的`$this-&gt;set()`替换.参数为一个数组,数组的key即为变量名.
</code></pre>

<p>b. 添加静态资源文件,如css,js等,需在layer中指定位置添加<code>$this-&gt;loadRes()</code>方法</p>
<pre><code>    namespace app\web\views;

    use Cross\MVC\View;

    class MainView extends View
    {
        function index($data = array())
        {   
            $this-&gt;addRes(&quot;css/style.css&quot;); 
            include $this-&gt;tpl(&quot;main/index&quot;);
        }
    }
</code></pre>

<blockquote>
<p>自定义app中的视图控制器基类的基类而不是直接继承<code>CoreView</code>,这样更灵活易扩展.</p>
</blockquote>
<h3>模板的使用</h3>
<p>根据使用的模板引擎选择支持的语法,这里以CrossPHP框架的原生视图为例.</p>
<h6>1. 使用默认视图控制器中的方法.</h6>
<p>a. 生成连接</p>
<pre><code>$this-&gt;link(&quot;controller:action&quot;, array('key'=&gt;'value'));    
</code></pre>

<blockquote>
<p>生成后的url中的连接由模块配置文件init.php中的url中type和dot控制  
</p>
</blockquote>
<p>b. 生成加密连接</p>
<pre><code>$this-&gt;slink(&quot;controller:action&quot;, array('key'=&gt;'value'));
</code></pre>

<p>唯一不同的是<code>array('key'=&gt;'value')</code> 部分是加密的	</p>
<blockquote>
<p>在控制器中调用 <code>$this-&gt;sparams()</code> 来还原加密前的参数</p>
</blockquote>
<p>c. 包含其他模板文件</p>
<pre><code>$this-&gt;tpl(&quot;page/p1&quot;);
</code></pre>

<blockquote>
<p>引入page目录下的p1.tpl.php文件</p>
</blockquote>
<h5>2. 在视图控制器中扩展</h5>
<pre><code>private function threadList( $data = array() )
{
    foreach($data as $d)
    {
        ?&gt;
        &lt;li&gt;
            &lt;a href=&quot;&lt;?php echo $this-&gt;link(&quot;read&quot;, array('id'=&gt;1)) ?&gt;&quot;&gt;标题&lt;/a&gt;
        &lt;/li&gt;
        &lt;?php
    }
}
</code></pre>

<p>在模板文件中用 <code>$this-&gt;threadList($data)</code> 调用.</p>
<blockquote>
<p>重复使用的,公共的的tpl可以放在app视图控制器自定义的基类中,保持模板代码的整洁</p>
</blockquote>
<h1>六. 使用第三方Model</h1>
<h5>1. 在module中扩展</h5>
<p>以使用<a href="http://medoo.in/" title="medoo">http://medoo.in/</a>为例，先下载medoo.min.php文件到lib目录， 使用Loader类中的import方法载入该类， 在控制器中重新指定<code>TestModule</code>的link属性为Medoo类的实例，然后就可以在action中调用<code>$this-&gt;link</code>来使用medoo提供的接口了。</p>
<pre><code>namespace modules\web;

use Cross\Core\Loader;
use Cross\MVC\Module;

Loader::import(&quot;::lib/medoo.min.php&quot;);

class TestModule extends Module
{
    function __construct()
    {
        parent::__construct();
        $config = $this-&gt;linkConfig()-&gt;get('mysql', 'db');

        $this-&gt;link = new \Medoo(array(
            'database_type' =&gt; 'mysql',
            'database_name' =&gt; $config['name'],
            'server' =&gt; $config['host'],
            'username' =&gt; $config['user'],
            'password' =&gt; $config['pass'],
        ));
    }

    function getUser()
    {
        return $this-&gt;link-&gt;get('back_acl_menu', '*', array(
                'id'    =&gt; 1,
            ));
    }
}
</code></pre>

<h5>2. 通过配置文件扩展</h5>
<pre><code>Loader::import(&quot;::lib/medoo.min.php&quot;);

.
.
.

return array(
    'mysql' =&gt; array(
        'db' =&gt; $db,
    ),  

    'medoo' =&gt; array(
        'db' =&gt;  function() use ($mysql_link) {
            return new \Medoo(array(
                'database_type' =&gt; 'mysql',
                'database_name' =&gt; $mysql_link['name'],
                'server' =&gt; $mysql_link['host'],
                'username' =&gt; $mysql_link['user'],
                'password' =&gt; $mysql_link['pass'],
            ));
        }
    ),

    'default'   =&gt;  array('mysql' =&gt; 'db')
);
</code></pre>

<p>然后在Module中这样使用</p>
<pre><code>namespace modules\web;

use Cross\Core\Loader;
use Cross\MVC\Module;       

class TestModule extends Module
{
    function __construct()
    {
        parent::__construct('medoo:db');
    }

    function getUser()
    {
        //通过$this-&gt;link访问mdeoo提供的api来使用数据库
        return $this-&gt;link;
    }
}
</code></pre>

<p>使用其他第三方model类似</p>
<h1>七.扩展模板系统</h1>
<h3>使用第三方PHP模版系统</h3>
<p>以添加Smarty为例,从<a href="http://www.smarty.net/download" title="http://www.smarty.net/download">http://www.smarty.net/download</a>下载你熟悉的smarty版本到项目根目录的lib中,本例以Smarty-3.1.17为例,新建一个SmartyView控制器继在你的视图控制器目录,使之承至CoreView类</p>
<ol>
<li>
<p>扩展系统
	namespace app\web\views;</p>
<pre><code>use Cross\MVC\View;

class SmartyView extends View
{
    function __construct()
    {
        parent::__construct();
        Loader::import(&quot;::lib/Smarty-3.1.17/libs/Smarty.class.php&quot;);
        $this-&gt;smarty = new Smarty;

        $this-&gt;smarty-&gt;debugging = true;
        $this-&gt;smarty-&gt;caching = true;
        $this-&gt;smarty-&gt;cache_lifetime = 120;
    }
}
</code></pre>

</li>
<li>
<p>使用
	namespace app\web\views;</p>
<pre><code>class MainView extends SmartyView
{
    function index($data = array())
    {   
        $this-&gt;smarty-&gt;assign(&quot;name&quot;, $data['name']);
        $this-&gt;smarty-&gt;assign(&quot;FirstName&quot;,array(&quot;John&quot;,&quot;Mary&quot;,&quot;James&quot;,&quot;Henry&quot;));
        $this-&gt;smarty-&gt;assign(&quot;LastName&quot;,array(&quot;Doe&quot;,&quot;Smith&quot;,&quot;Johnson&quot;,&quot;Case&quot;));    
        $this-&gt;smarty-&gt;assign(&quot;contacts&quot;, array(
                array(&quot;phone&quot; =&gt; &quot;1&quot;, &quot;fax&quot; =&gt; &quot;2&quot;, &quot;cell&quot; =&gt; &quot;3&quot;),
                array(&quot;phone&quot; =&gt; &quot;555-4444&quot;, &quot;fax&quot; =&gt; &quot;555-3333&quot;, &quot;cell&quot; =&gt; &quot;760-1234&quot;)
            ));

        $this-&gt;smarty-&gt;display( $this-&gt;tpl(&quot;main/index&quot;) );
    }
}
</code></pre>

</li>
</ol>
<h3>使用JS模板引擎</h3>
<p>以添加artTemplate模板引擎为例, 从<a href="https://github.com/aui/artTemplate" title="https://github.com/aui/artTemplate">https://github.com/aui/artTemplate</a>下载最新版本,放在htdocs/static/lib目录下.</p>
<ol>
<li>
<p>修改模板根目录下的default.layer.php文件,在head部分中加入引擎的连接</p>
<pre><code>&lt;script src=&quot;&lt;?php echo $this-&gt;res(&quot;lib/artTemplate/dist/template-simple.js&quot;) ?&gt;&quot;&gt;&lt;/script&gt;
</code></pre>

<p>为content所在的父级div添加一个id属性</p>
<pre><code>&lt;div id=&quot;layer-content&quot;&gt;
    &lt;?php echo isset($content)?$content:'暂无内容' ?&gt;
&lt;/div&gt;
</code></pre>

<p>在<code>&lt;/body&gt;</code>前添加如下JS代码</p>
<pre><code>&lt;script type=&quot;text/javascript&quot;&gt;
    var html = template.render('layer-content', &lt;?php echo isset($jsonData)?$jsonData:'{}' ?&gt;);
    document.getElementById('layer-content').innerHTML = html;
&lt;/script&gt;
</code></pre>

</li>
<li>
<p>在视图视图控制器类中使用. 通过<code>$this-&gt;set()</code>把模板引擎需要的数据传送到layer.</p>
<pre><code>namespace app\web\views;

use Cross\MVC\View;

class MainView extends View
{
    function index($data = array())
    {   
        $this-&gt;set(array(
           'jsonData' =&gt;  json_encode($data)
        ));

        include $this-&gt;tpl(&quot;main/index&quot;);
    }
}
</code></pre>

</li>
</ol>
<blockquote>
<p>以上两种方式都保留了CrossPHP视图的layer功能.</p>
</blockquote>
<h1>八.与第三方程序交互</h1>
<h3>Yar</h3>
<pre><code>require '../../crossboot.php';

$conf = array(
    'server'    =&gt;  array(
        'id'    =&gt;  2,
        'name'  =&gt;  'test',
        'ver'   =&gt;  '1.1',
    ),
);  

$service = new Yar_Server( Cross::loadApp( 'api', $conf ) );
$service-&gt;handle();
</code></pre>

<h3>ZMQ</h3>
<pre><code>require '../../crossboot.php';

$conf = array(
    'server'    =&gt;  array(
        'id'    =&gt;  2,
        'name'  =&gt;  'test',
        'ver'   =&gt;  '1.1',
    ),
);

$context = new ZMQContext(1);

//  Socket to talk to clients
$responder = new ZMQSocket($context, ZMQ::SOCKET_REP);
$responder-&gt;bind(&quot;tcp://127.0.0.1:5678&quot;);

while (true) {
    //  Wait for next request from client
    $request = $responder-&gt;recv();

    $request_array = array();
    parse_str( $request, $request_array );

    $controller = isset($request_array['mode']) ? $request_array['mode'] : '';
    if( $controller )
    {
        if(false !== strpos($controller, '.')) {
            $controller = str_replace('.', ':', $controller);
        } else {
            $controller = &quot;{$controller}:index&quot;;
        }
        unset($request_array['mode']);
    } else {
        $controller = 'main:index';
    }

    ob_start(); 
    try {

        Cross::loadApp( 'api', $conf )-&gt;get( $controller, $request_array );

    } catch(Exception $e) { 
        $e-&gt;getMessage();   
    }

    $req = ob_get_clean();
    $responder-&gt;send( $req );
}
</code></pre>

<p>更多使用方法请在使用中去发现,如有疑问请加QQ群:120801063</p>

</body>
</html>
<!-- This document was created with MarkdownPad, the Markdown editor for Windows (http://markdownpad.com) -->
